/**
	Copyright (c) 2009 Ozazo Pvt Ltd, INDIA

	Permission is hereby granted, free of charge, to any person or organization 
	obtaining a copy of this software and associated  documentation  files (the 
	"Software"), to deal in the Software without restriction, including without 
	limitation the rights to use, copy, modify, merge, publish, distribute, sub
	license, and/or sell copies of the Software, and to permit persons  to whom 
	the Software is furnished to do so, subject to the following conditions:
	
	The above copyright notice and  this permission notice shall be included in 
	all copies or substantial portions of the Software.
	
	THE SOFTWARE IS PROVIDED "AS IS",  WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING  BUT NOT  LIMITED  TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR  COPYRIGHT  HOLDERS  BE  LIABLE  FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY,  WHETHER  IN  AN  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
	FROM,  OUT  OF  OR  IN  CONNECTION  WITH  THE  SOFTWARE OR THE USE OR OTHER 
	DEALINGS IN THE SOFTWARE.
 */
package com.ozazo.wave.robots.engines;

import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.logging.Logger;

import com.ozazo.wave.robots.fw.engines.BlipDataParserInterface;
import com.ozazo.wave.robots.fw.engines.Commands;
import com.ozazo.wave.robots.fw.search.OpenSearchResult;

/**
 * @author: Araf Karsh Hamid
 * @date:   20091110
 * @version 1.0
 * @seriel 20091121102030
 */

public class BlipDataParser implements BlipDataParserInterface {
	
	private final Logger log;
	
	public BlipDataParser() {
		this(Logger.getLogger("BlipDataParser"));
	}
	
	public BlipDataParser(Logger _log) {
		log = _log;
	}

	/**
		In Java, you compile a regular expression by using the Pattern.compile() class 
		factory. This factory returns an object of type Pattern. 
		E.g.: Pattern myPattern = Pattern.compile("regex"); 
		You can specify certain options as an optional second parameter. 
		Pattern.compile("regex", Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE) 
		makes the regex case insensitive for US ASCII characters, causes the dot to match
		line breaks and causes the start and end of string anchors to match at embedded 
		line breaks as well. When working with Unicode strings, specify 
		Pattern.UNICODE_CASE if you want to make the regex case insensitive for all 
		characters in all languages. You should always specify Pattern.CANON_EQ to ignore
		differences in Unicode encodings, unless you are sure your strings contain only 
		US ASCII characters and you want to increase performance.		

		Predefined character classes

		character class	Description
		\d	   	A digit. Equivalent to [0-9].
		\D	   	A nondigit. Equivalent to [^0-9].
		\s	   	A whitespace character. Equivalent to [ \t\n\x0B\f\r].
		\S	   	A nonwhitespace character. Equivalent to [^\s].
		\w	   	A word character. Equivalent to [a-zA-Z_0-9].
		\W	   	A nonword character. Equivalent to [^\w].


		Boundary matchers

		Boundary 	Description
		^		The beginning of a line
		$		The end of a line
		\b		A word boundary
		\B		A nonword boundary
		\A		The beginning of the text
		\G		The end of the previous match
		\Z		The end of the text (but for the final line terminator, if any)
		\z		The end of the text

		Embedded flag expressions

		Matchers assume certain defaults, such as case-sensitive pattern matching. A program may
		override any default by using an embedded flag expression, that is, a regex construct specified
		as parentheses metacharacters surrounding a question mark metacharacter (?) followed by a
		specific lowercase letter. Pattern recognizes the following embedded flag expressions:

		(?i): enables case-insensitive pattern matching. Example: java RegexDemo (?i)tree
		Treehouse matches tree with Tree. Case-sensitive pattern matching is the default.

		(?x): permits whitespace and comments beginning with the # metacharacter to appear in
		a pattern. A matcher ignores both. Example: java RegexDemo ".at(?x)#match hat, cat,
		and so on" matter matches .at with mat. By default, whitespace and comments are not
		permitted; a matcher regards them as characters that contribute to a match.

		(?s): enables dotall mode. In that mode, the period metacharacter matches line
		terminators in addition to any other character. Example: java RegexDemo (?s). \n
		matches . with \n. Nondotall mode is the default: line-terminator characters do not
		match.

		(?m): enables multiline mode. In multiline mode, ^ and $ match just after or just before
		(respectively) a line terminator or the text's end. Example: java RegexDemo (?m)^.ake
		make\rlake\n\rtake matches .ake with make, lake, and take. Non-multiline mode is the
		default: ^ and $ match only at the beginning and end of the entire text.

		(?u): enables Unicode-aware case folding. This flag works with (?i) to perform caseinsensitive
		matching in a manner consistent with the Unicode Standard. The default: caseinsensitive
		matching that assumes only characters in the US-ASCII character set match.

		(?d): enables Unix lines mode. In that mode, a matcher recognizes only the \n line
		terminator in the context of the ., ^, and $ metacharacters. Non-Unix lines mode is the
		default: a matcher recognizes all terminators in the context of the aforementioned
		metacharacters.
		
	*/

	private static final String regex = "(?ism)([-/](w|wd|ltx)\\s)((\\w*\\b)|([\"]([^\"]+)[\"])|([']([^']+)[']))";
	private static final String regexRealTime = "(?ism)([-/](w|wd|ltx)\\s)(((\\w*\\b)|([\"]([^\"]+)[\"])|([']([^']+)[']))(:|;|,|\\.|\\s\\w+))";

	// Instances of Pattern class are immutable and are safe for use by multiple concurrent threads.
	private static final Pattern pattern		= Pattern.compile(regex, Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE);
	private static final Pattern patternRT		= Pattern.compile(regexRealTime, Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE);

	/**
	 * Parses the Blip text and returns Commands for further processing.
	 * For Example. From the following sentence marked with /w 
	 *  
	 * The /w "Battle of Stalingrad" was a major battle of World War II in which Nazi /w Germany and its 
	 * allies fought the Soviet Union for control of the city of Stalingrad (now Volgograd) in southwestern 
	 * /wd Russia.
	 * 
	 * The Commands Object will contain the following
	 * 
	 *  /w  "Battle of Stalingrad"
	 *  /w  Germany
	 *  /wd Russia
	 * 
	 * These Commands will be further processed by other engines to search the net for links, descriptions etc.
	 * With this method the text will be processed in NON Real Time mode (ie for Blip Submitted Mode).
	 * 
	 * @param String blipText, boolean realTime
	 * @return List<Commands>
	 */
	
	public ArrayList<Commands> parse(String blipText) {
		return parse(blipText, false);
	}
	
	
	/**
	 * Parses the Blip text and returns Commands for further processing.
	 * For Example. From the following sentence marked with /w 
	 *  
	 * The /w "Battle of Stalingrad" was a major battle of World War II in which Nazi /w Germany and its 
	 * allies fought the Soviet Union for control of the city of Stalingrad (now Volgograd) in southwestern 
	 * /wd Russia.
	 * 
	 * The Commands Object will contain the following
	 * 
	 *  /w  "Battle of Stalingrad"
	 *  /w  Germany
	 *  /wd Russia
	 * 
	 * These Commands will be further processed by other engines to search the net for links, descriptions etc.
	 * Second argument is to check if the text needs to be processed in real time or not.
	 * 
	 * @param String blipText, boolean realTime
	 * @return List<Commands>
	 */

	public ArrayList<Commands> parse(String _blipText, boolean isRealTime) {
		ArrayList<Commands> list = new ArrayList<Commands>();
		if(_blipText == null) {
			return list;			// Returns EMPTY Command List
		}
		Matcher m = (isRealTime) ? patternRT.matcher(_blipText) : pattern.matcher(_blipText);
		System.out.println("\nINPUT: " + _blipText);
		if(isRealTime) {
			System.out.println("REGEX: " + regexRealTime + "\r\n");			
		} else {
			System.out.println("REGEX: " + regex + "\r\n");
		}
		while (m.find()) {
			String text = m.group(0).trim();		
			String oCmd = m.group(1).trim();
			String cmd 	= m.group(2).trim();
			String oVal = (isRealTime) ? m.group(4).trim() : m.group(3).trim();
			String val	= oVal;
			if(oVal.startsWith("\"")) {
				val = oVal.replace("\"", "");
			} else if (oVal.startsWith("'")) {
				val = oVal.replace("'", "");
			}
			if(val != null) {
				Commands cmds = new Commands(cmd, oCmd, val, oVal);
				list.add(cmds);
			}	
			System.out.println("("+m.groupCount()+") MATCH: Txt=["+text+"] cmd=["+cmd+"] oCmd=["+m.group(1)+"] val=["+val+"] oVal=["+oVal+"]");
			// System.out.println(m.group(0)+"|"+m.group(1)+"|"+m.group(2)+"|"+m.group(3)+"|"+m.group(4)+"|"+m.group(5)+"|"+m.group(6)+"|");
		}
		return list;	
	}	
}